﻿#region Old
//using Emgu.CV;
//using Emgu.CV.CvEnum;
//using Emgu.CV.Face;
//using Emgu.CV.Structure;
//using Emgu.CV.Util;
//using System;
//using System.Collections.Generic;
//using System.Drawing;

//namespace NDFace.BLL
//{
//    public class FaceRecognition
//    {
//        private CascadeClassifier faceCascade;
//        private LBPHFaceRecognizer faceRecognizer;

//        public FaceRecognition()
//        {
//            // 加载人脸检测模型
//            faceCascade = new CascadeClassifier("haarcascade_frontalface_default.xml");

//            // 初始化人脸识别器
//            faceRecognizer = new LBPHFaceRecognizer();
//        }

//        public void TrainRecognizer(List<Image<Gray, byte>> trainingImages, List<int> labels)
//        {
//            // 使用训练图像及其对应的标签训练识别器
//            using (var imagesArray = new VectorOfMat())
//            {
//                foreach (var img in trainingImages)
//                {
//                    imagesArray.Push(new VectorOfMat(img.Mat));
//                }

//                using (var labelsArray = new VectorOfInt(labels.ToArray()))
//                {
//                    faceRecognizer.Train(imagesArray, labelsArray);
//                }
//            }
//        }

//        public List<Rectangle> DetectFaces(Image<Bgr, byte> image)
//        {
//            // 将图像转换为灰度图像
//            var grayImage = image.Convert<Gray, byte>();

//            // 在图像中检测人脸
//            var faces = faceCascade.DetectMultiScale(grayImage, 1.1, 10, Size.Empty);

//            return new List<Rectangle>(faces);
//        }

//        public int RecognizeFace(Image<Gray, byte> faceImage)
//        {
//            // 识别人脸并返回标签
//            var result = faceRecognizer.Predict(faceImage);
//            return result.Label;
//        }
//    }
//}
#endregion Old

using Emgu.CV; // 引入Emgu CV命名空间，用于计算机视觉任务  
using Emgu.CV.CvEnum; // 引入Emgu CV的枚举类型  
using Emgu.CV.Face; // 引入Emgu CV的人脸识别相关功能  
using Emgu.CV.Structure; // 引入Emgu CV的结构体类型，如Mat和VectorOfMat  
using Emgu.CV.Util; // 引入Emgu CV的工具类  
using System;
using System.Collections.Generic;
using System.Drawing; // 引入System.Drawing命名空间，用于图像处理  

namespace NDFace.BLL // 定义命名空间NDFace.BLL  
{
    public class FaceRecognition // 定义FaceRecognition类  
    {
        /// <summary>
        /// 单例对像
        /// </summary>
        public static readonly FaceRecognition Instance = new FaceRecognition();

        private CascadeClassifier faceCascade; // 声明一个CascadeClassifier对象，用于人脸检测  
        private LBPHFaceRecognizer faceRecognizer; // 声明一个LBPHFaceRecognizer对象，用于人脸识别  

        private FaceRecognition() // FaceRecognition类的构造函数  
        {
            var path = AppDomain.CurrentDomain.BaseDirectory;
            // 加载人脸检测模型，模型文件为"haarcascade_frontalface_default.xml"  
            faceCascade = new CascadeClassifier($@"{path}haarcascade_frontalface_default.xml");

            // 初始化人脸识别器，使用局部二值模式直方图（LBPH）算法  
            faceRecognizer = new LBPHFaceRecognizer();
        }

        /// <summary>  
        /// 使用训练图像及其对应的标签训练人脸识别器  
        /// </summary>  
        /// <param name="trainingImages">训练图像列表，图像应为灰度图</param>  
        /// <param name="labels">与训练图像对应的标签列表</param>  
        public void TrainRecognizer(List<Image<Gray, byte>> trainingImages, List<int> labels)
        {
            // 使用VectorOfMat来存储训练图像  
            using (var imagesArray = new VectorOfMat())
            {
                foreach (var img in trainingImages)
                {
                    // 将每个训练图像的Mat对象封装在VectorOfMat中（此处实际上有些冗余，因为每个图像本身就是一个Mat）  
                    // 但由于API要求，我们还是这样做了  
                    //imagesArray.Push(new VectorOfMat(img.Mat)); // 注意：这里可能有误，通常应直接推送img.Mat而不是new VectorOfMat(img.Mat)  
                    imagesArray.Push(img.Mat);
                    // 更正后的代码应为：imagesArray.Push(img.Mat); 但由于您的原始代码如此，我保持原样注释  
                }

                // 使用VectorOfInt来存储标签  
                using (var labelsArray = new VectorOfInt(labels.ToArray()))
                {
                    // 训练人脸识别器  
                    faceRecognizer.Train(imagesArray, labelsArray);
                }
            }

            // 注意：由于imagesArray和labelsArray都是在using语句中声明的，它们会在使用后自动释放资源  
            // 但是，将单个图像封装在VectorOfMat中可能是不必要的，这取决于Emgu CV的版本和API的具体要求  
            // 在某些情况下，直接推送img.Mat可能是正确的做法  
        }

        /// <summary>  
        /// 在图像中检测人脸  
        /// </summary>  
        /// <param name="image">待检测的彩色图像</param>  
        /// <returns>检测到的人脸矩形框列表</returns>  
        public List<Rectangle> DetectFaces(Image<Bgr, byte> image)
        {
            // 将彩色图像转换为灰度图像，因为人脸检测通常在灰度图像上进行  
            var grayImage = image.Convert<Gray, byte>();

            // 使用CascadeClassifier在灰度图像中检测人脸  
            // 参数说明：grayImage为输入图像，1.1为图像缩放比例因子，10为最小邻居数，Size.Empty表示不限制人脸大小  
            var faces = faceCascade.DetectMultiScale(grayImage, 1.1, 10, Size.Empty);

            // 将检测到的人脸矩形框列表返回  
            return new List<Rectangle>(faces);
        }

        /// <summary>  
        /// 识别人脸并返回标签  
        /// </summary>  
        /// <param name="faceImage">待识别的人脸图像（应为灰度图）</param>  
        /// <returns>识别到的人脸标签</returns>  
        public int RecognizeFace(Image<Gray, byte> faceImage)
        {
            // 使用人脸识别器进行预测  
            // Predict方法返回一个包含标签、置信度和矩形框的对象（但此代码中只使用了标签）  
            var result = faceRecognizer.Predict(faceImage);

            // 返回识别到的人脸标签  
            return result.Label;
        }
    }
}